#ifdef __STDC_VERSION__
#if __STDC_VERSION__ < 199901L
#error Rok 1999 już dawno za nami. Czas uaktualnić kompilator!
#endif
#else
#error Rok 1999 już dawno za nami. Czas uaktualnić kompilator!
#endif

/* Ten plik to tylko interfejs użytkownika.
 * Właściwy kod implementujący kryptografię
 * znajduje się w pliku przeksztalcenia.c
 */

#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<inttypes.h>
#include<gtk/gtk.h>
#include"przeksztalcenia.h"

GtkWidget *okno;
GtkWidget *panel;
GtkWidget *h1;
GtkWidget *h2;
GtkWidget *szyfruj;
GtkWidget *szydefrujmy;
GtkWidget *deszyfruj;
GtkWidget *generuj;
GtkWidget *klucz;
GtkWidget *tekst1;
GtkWidget *tekst2;
GtkWidget *separator;
GtkTextBuffer *bufork;
GtkTextBuffer *bufor1;
GtkTextBuffer *bufor2;
GtkWidget *wejscie;
GtkWidget *wyjscie;
char* input=NULL;
char* output=NULL;
mpz_t G;
mpz_t P;
/* Dwie duże liczby pseudopierwsze */
const unsigned char * const gg="adc0f13a0ce06b253c26b21be3ba47f6dc65238c6fdca4da2b0c89a995af87c0481c2e6adb02474114bef96d0aa229058b7ec91940c365c04a00e409dcd2469b";
const unsigned char * const pp="ea8434f51293b3c2cd231d5c4e61116836711dca76c0bc57cfed21977746712844033377961e2fe83e6ab265f4ede4b9d158a1c32534c8ba40e65936130589f5";


void szyfruj_clicked(GtkButton *obiekt, gpointer dane)
{
   GtkTextIter pbufork, kbufork, pbufor1, kbufor1;
   GtkWidget * dialog;
   unsigned char *klucz, *tekst, *kod;
   mpz_t k;
   unsigned int i;
   size_t dlugosc;

   mpz_init(k);
   gtk_text_buffer_get_start_iter(bufork,&pbufork);
   gtk_text_buffer_get_end_iter(bufork,&kbufork);
   gtk_text_buffer_get_start_iter(bufor1,&pbufor1);
   gtk_text_buffer_get_end_iter(bufor1,&kbufor1);
   klucz=gtk_text_buffer_get_text(bufork,&pbufork,&kbufork,FALSE);
   tekst=gtk_text_buffer_get_text(bufor1,&pbufor1,&kbufor1,FALSE);
   if(strlen(klucz)!=128)
   {
      dialog=gtk_message_dialog_new(GTK_WINDOW(okno),GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_NONE,"Błędna ilość bajtów klucza. Wprowadź liczbę szesnastkową składającą się z 128 znaków");
      gtk_widget_show_all(dialog);
      free(klucz);
      free(tekst);
      mpz_clear(k);
      return;
   }
   gmp_sscanf(klucz,"%128Zx",k);
   ustawZiarno(k);

   dlugosc=strlen(tekst);
   kod=(unsigned char*)malloc(sizeof(unsigned char)*(2*dlugosc+1));
   kod[dlugosc*2]='\0';
   for(i=0;i<dlugosc;++i)
   {
      sprintf(&(kod[2*i]),"%02hhx",szydefruj(tekst[i]));
   }
   gtk_text_buffer_set_text(bufor2,kod,-1);
   free(klucz);
   free(tekst);
   free(kod);
   mpz_clear(k);
}

void deszyfruj_clicked(GtkButton *obiekt, gpointer dane)
{
   GtkTextIter pbufork, kbufork, pbufor2, kbufor2;
   GtkWidget * dialog;
   unsigned char *klucz, *tekst, *kod;
   mpz_t k;
   unsigned int i;
   size_t dlugosc;

   mpz_init(k);
   gtk_text_buffer_get_start_iter(bufork,&pbufork);
   gtk_text_buffer_get_end_iter(bufork,&kbufork);
   gtk_text_buffer_get_start_iter(bufor2,&pbufor2);
   gtk_text_buffer_get_end_iter(bufor2,&kbufor2);
   klucz=gtk_text_buffer_get_text(bufork,&pbufork,&kbufork,FALSE);
   kod=gtk_text_buffer_get_text(bufor2,&pbufor2,&kbufor2,FALSE);
   if(strlen(klucz)!=128)
   {
      dialog=gtk_message_dialog_new(GTK_WINDOW(okno),GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_NONE,"Błędna ilość bajtów klucza. Wprowadź liczbę szesnastkową składającą się z 128 znaków");
      gtk_widget_show_all(dialog);
      free(klucz);
      free(kod);
      mpz_clear(k);
      return;
   }
   gmp_sscanf(klucz,"%128Zx",k);
   ustawZiarno(k);

   dlugosc=strlen(kod);
   tekst=(unsigned char*)malloc(sizeof(unsigned char)*(dlugosc/2+1));
   tekst[dlugosc/2]='\0';
   for(i=0;i<dlugosc/2;++i)
   {
      sscanf(&(kod[2*i]),"%2hhx",&(tekst[i]));
      tekst[i]=szydefruj(tekst[i]);
   }
   gtk_text_buffer_set_text(bufor1,tekst,-1);
   free(klucz);
   free(tekst);
   free(kod);
   mpz_clear(k);
}

void szydefrujmy_clicked(GtkButton *obiekt, gpointer dane)
{
   GtkTextIter pbufork, kbufork;
   GtkWidget * dialog;
   unsigned char *klucz;
   unsigned int i;
   FILE *wejscie, *wyjscie;
   int bufor;
   mpz_t k;

   mpz_init(k);
   gtk_text_buffer_get_start_iter(bufork,&pbufork);
   gtk_text_buffer_get_end_iter(bufork,&kbufork);
   klucz=gtk_text_buffer_get_text(bufork,&pbufork,&kbufork,FALSE);
   if(strlen(klucz)!=128)
   {
      dialog=gtk_message_dialog_new(GTK_WINDOW(okno),GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_NONE,"Błędna ilość bajtów klucza. Wprowadź liczbę szesnastkową składającą się z 128 znaków");
      gtk_widget_show_all(dialog);
      free(klucz);
      mpz_clear(k);
      return;
   }

   gmp_sscanf(klucz,"%128Zx",k);
   ustawZiarno(k);

   wejscie=fopen(input,"r");
   wyjscie=fopen(output,"w");
   if(wejscie==NULL || wejscie==NULL)
   {
      dialog=gtk_message_dialog_new(GTK_WINDOW(okno),GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_NONE,"Błąd przy otwieraniu pliku.");
      gtk_widget_show_all(dialog);
      free(klucz);
      mpz_clear(k);
      return;
   }
   while(!feof(wejscie))
   {
      bufor=fgetc(wejscie);
      if(bufor==EOF)
	 break;
      bufor=fputc(szydefruj(bufor),wyjscie);
      if(bufor==EOF)
      {
	 dialog=gtk_message_dialog_new(GTK_WINDOW(okno),GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_NONE,"Błąd zapisu.");
	 gtk_widget_show_all(dialog);
	 break;
      }
   }
   fclose(wejscie);
   fclose(wyjscie);
   free(klucz);
   mpz_clear(k);
}

void generuj_clicked(GtkButton *obiekt, gpointer dane)
{
   mpz_t liczba;
   unsigned char napis[bityPierwszej*2/8+1];
   napis[bityPierwszej*2/8]='\0';

   mpz_init(liczba);
   do
   {
      generujPierwsza(liczba);
   }
   while((mpz_cmp(liczba,G)==0) || (mpz_cmp(liczba,P)==0));
   gmp_snprintf(napis,bityPierwszej*2/8+1,"%0*Zx",bityPierwszej*2/8,liczba);
   gtk_text_buffer_set_text(bufork,napis,-1);
}

void wejscie_clicked(GtkButton *obiekt, gpointer dane)
{
   GtkWidget *pliki;
   pliki=gtk_file_chooser_dialog_new(NULL,GTK_WINDOW(okno),GTK_FILE_CHOOSER_ACTION_OPEN,GTK_STOCK_OPEN,GTK_RESPONSE_ACCEPT,GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,NULL);
   if( gtk_dialog_run(GTK_DIALOG(pliki)) == GTK_RESPONSE_ACCEPT)
   {
      if(input!=NULL)
	 free(input);
      input=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pliki));
      gtk_button_set_label(GTK_BUTTON(wejscie),input);
   }
   gtk_widget_destroy(pliki);
}

void wyjscie_clicked(GtkButton *obiekt, gpointer dane)
{
   GtkWidget *pliki;
   pliki=gtk_file_chooser_dialog_new(NULL,GTK_WINDOW(okno),GTK_FILE_CHOOSER_ACTION_SAVE,GTK_STOCK_SAVE,GTK_RESPONSE_ACCEPT,GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,NULL);
   if( gtk_dialog_run(GTK_DIALOG(pliki)) == GTK_RESPONSE_ACCEPT)
   {
      if(output!=NULL)
	 free(output);
      output=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pliki));
      gtk_button_set_label(GTK_BUTTON(wyjscie),output);
   }
   gtk_widget_destroy(pliki);
}

int main(int argc, char *argv[])
{
   inicjalizuj();
   gtk_init(&argc,&argv);
   mpz_init(G);
   mpz_init(P);

   mpz_set_str(G,gg,16);
   mpz_set_str(P,pp,16);
   ustawG(G);
   ustawP(P);

   okno=gtk_window_new(GTK_WINDOW_TOPLEVEL);
   g_signal_connect(okno,"destroy",G_CALLBACK(gtk_main_quit),NULL);

   panel=gtk_hpaned_new();
   gtk_container_add(GTK_CONTAINER(okno),panel);

   h1=gtk_vbox_new(FALSE,0);
   gtk_paned_pack1(GTK_PANED(panel),h1,TRUE,TRUE);

   h2=gtk_vbox_new(FALSE,0);
   gtk_paned_pack2(GTK_PANED(panel),h2,TRUE,TRUE);

   klucz=gtk_text_view_new();
   bufork=gtk_text_view_get_buffer(GTK_TEXT_VIEW(klucz));
   gtk_text_buffer_set_text(bufork,"Tu wpisz tekst klucza",-1);
   gtk_box_pack_start(GTK_BOX(h1),klucz,TRUE,TRUE,0);

   generuj=gtk_button_new_with_label("generuj");
   g_signal_connect(generuj,"clicked",G_CALLBACK(generuj_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h1),generuj,TRUE,TRUE,0);

   separator=gtk_hseparator_new();
   gtk_box_pack_start(GTK_BOX(h1),separator,TRUE,TRUE,0);

   tekst1=gtk_text_view_new();
   bufor1=gtk_text_view_get_buffer(GTK_TEXT_VIEW(tekst1));
   gtk_text_buffer_set_text(bufor1,"Tu wpisz tekst do zaszyfrowania",-1);
   gtk_box_pack_start(GTK_BOX(h1),tekst1,TRUE,TRUE,0);

   szyfruj=gtk_button_new_with_label("szyfruj");
   g_signal_connect(szyfruj,"clicked",G_CALLBACK(szyfruj_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h1),szyfruj,TRUE,TRUE,0);

   deszyfruj=gtk_button_new_with_label("deszyfruj");
   g_signal_connect(deszyfruj,"clicked",G_CALLBACK(deszyfruj_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h1),deszyfruj,TRUE,TRUE,0);

   tekst2=gtk_text_view_new();
   bufor2=gtk_text_view_get_buffer(GTK_TEXT_VIEW(tekst2));
   gtk_box_pack_start(GTK_BOX(h1),tekst2,TRUE,TRUE,0);

   wejscie=gtk_button_new_with_label("wybierz plik wejściowy");
   g_signal_connect(wejscie,"clicked",G_CALLBACK(wejscie_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h2),wejscie,TRUE,TRUE,0);

   wyjscie=gtk_button_new_with_label("wybierz plik wyjściowy");
   g_signal_connect(wyjscie,"clicked",G_CALLBACK(wyjscie_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h2),wyjscie,TRUE,TRUE,0);

   szydefrujmy=gtk_button_new_with_label("szyfruj/deszyfruj");
   g_signal_connect(szydefrujmy,"clicked",G_CALLBACK(szydefrujmy_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(h2),szydefrujmy,TRUE,TRUE,0);

   gtk_widget_show_all(okno);
   gtk_main();
   return EXIT_SUCCESS;
}
